/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "spatial_awareness_mgr_client.h"

#include <datetime_ex.h>
#include <if_system_ability_manager.h>
#include <ipc_skeleton.h>
#include <iservice_registry.h>
#include <string_ex.h>
#include <system_ability_definition.h>

#include "spatial_awareness_common.h"

namespace OHOS {
namespace Msdp {
SpatialAwarenessMgrClient::SpatialAwarenessMgrClient() {}
SpatialAwarenessMgrClient::~SpatialAwarenessMgrClient()
{
    if (proxy_ != nullptr) {
        auto remoteObject = proxy_->AsObject();
        if (remoteObject != nullptr) {
            remoteObject->RemoveDeathRecipient(deathRecipient_);
        }
    }
}

ErrCode SpatialAwarenessMgrClient::Connect()
{
    std::lock_guard<std::mutex> lock(mutex_);
    if (proxy_ != nullptr) {
        return ERR_OK;
    }

    sptr<ISystemAbilityManager> sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    if (sam == nullptr) {
        SPATIAL_LOGE(MODULE_INNERKIT, "%{public}s:Failed to get Registry!", __func__);
        return E_GET_SYSTEM_ABILITY_MANAGER_FAILED;
    }

    sptr<IRemoteObject> remoteObject_ = sam->CheckSystemAbility(MSDP_SPATIAL_AWARENESS_SERVICE_ID);
    if (remoteObject_ == nullptr) {
        SPATIAL_LOGE(MODULE_INNERKIT, "GetSystemAbility failed!");
        return E_GET_SPATIAL_AWARENESS_SERVICE_FAILED;
    }

    deathRecipient_ = sptr<IRemoteObject::DeathRecipient>(new SpatialAwarenessMgrDeathRecipient());
    if (deathRecipient_ == nullptr) {
        SPATIAL_LOGE(MODULE_INNERKIT, "%{public}s :Failed to create SpatialAwarenessMgrDeathRecipient!", __func__);
        return ERR_NO_MEMORY;
    }

    if ((remoteObject_->IsProxyObject()) && (!remoteObject_->AddDeathRecipient(deathRecipient_))) {
        SPATIAL_LOGE(MODULE_INNERKIT, "%{public}s :Add death recipient to PowerMgr service failed.", __func__);
        return E_ADD_DEATH_RECIPIENT_FAILED;
    }

    proxy_ = iface_cast<ISpatialAwarenessMgr>(remoteObject_);
    SPATIAL_LOGI(MODULE_INNERKIT, "%{public}s :Connecting ThermalMgrService success.", __func__);
    return ERR_OK;
}

void SpatialAwarenessMgrClient::ResetProxy(const wptr<IRemoteObject>& remote)
{
    std::lock_guard<std::mutex> lock(mutex_);
    RETURN_IF(proxy_ == nullptr);

    auto serviceRemote = proxy_->AsObject();
    if ((serviceRemote != nullptr) && (serviceRemote == remote.promote())) {
        serviceRemote->RemoveDeathRecipient(deathRecipient_);
        proxy_ = nullptr;
    }
}

void SpatialAwarenessMgrClient::SpatialAwarenessMgrDeathRecipient::OnRemoteDied(const wptr<IRemoteObject>& remote)
{
    if (remote == nullptr) {
        SPATIAL_LOGE(MODULE_INNERKIT, "SpatialAwarenessMgrDeathRecipient::OnRemoteDied failed, remote is nullptr.");
        return;
    }
    SpatialAwarenessMgrClient::GetInstance().ResetProxy(remote);
    SPATIAL_LOGI(MODULE_INNERKIT, "SpatialAwarenessMgrDeathRecipient::Recv death notice.");
}

void SpatialAwarenessMgrClient::SubscribeSpatialLocationRelationship(const SpatialLocationMode &mode,
    const SpatialDeviceInfo &info, const sptr<ISpatialLocationCallback>& callback)
{
    RETURN_IF((callback == nullptr) || (Connect() != ERR_OK));
    SPATIAL_LOGI(MODULE_INNERKIT, "%{public}s.", __func__);
    proxy_->SubscribeSpatialLocationRelationship(mode, info, callback);
}

void SpatialAwarenessMgrClient::UnSubscribeSpatialLocationRelationship(const SpatialLocationMode &mode,
    const SpatialDeviceInfo &info, const sptr<ISpatialLocationCallback>& callback)
{
    RETURN_IF((callback == nullptr) || (Connect() != ERR_OK));
    SPATIAL_LOGI(MODULE_INNERKIT, "%{public}s.", __func__);
    proxy_->UnSubscribeSpatialLocationRelationship(mode, info, callback);
}
} // namespace Msdp
} // namespace OHOS